package com.glsc.ngateway.platform.config;

import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.TimeUnit;

@Configuration
@EnableCaching //开启缓存
public class CaffeinConfig {

    @Autowired
    private CacheStatsCounter cacheStatsCounter;

    /**
     * Caffeine 配置说明：
     * initialCapacity: 初始的缓存空间大小。
     * maximumSize: 缓存的最大数量。
     * maximumWeight: 缓存的最大权重。
     * expireAfterAccess: 最后一次读或写操作后经过指定时间过期。
     * expireAfterWrite: 最后一次写操作后经过指定时间过期。
     * refreshAfterWrite: 创建缓存或者最近一次更新缓存后经过指定时间间隔，刷新缓存。
     * weakKeys: 打开key的弱引用。弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中，一旦发现了只具有弱引用的对象，不管当前内存空间足够与否，都会回收它的内存。
     * weakValues：打开value的弱引用。
     * softValues：打开value的软引用。软引用： 如果一个对象只具有软引用，则内存空间足够，垃圾回收器就不会回收它；如果内存空间不足了，就会回收这些对象的内存。
     * recordStats：开发统计功能。
     * removalListener：缓存淘汰监听器，配置监听器后，每个条目淘汰时都会调用该监听器
     * writer：writer监听器其实提供了两个监听，一个是缓存写入或更新是的write，一个是缓存淘汰时的delete，每个条目淘汰时都会调用该监听器
     * <p>
     * 配套注解:
     *
     * @Cacheable 触发缓存入口（这里一般放在创建和获取的方法上）
     * @CacheEvict 触发缓存的eviction（用于删除的方法上）
     * @CachePut 更新缓存且不影响方法执行（用于修改的方法上，该注解下的方法始终会被执行）
     * @Caching 将多个缓存组合在一个方法上（该注解可以允许一个方法同时设置多个注解）
     * @CacheConfig 在类级别设置一些缓存相关的共同配置（与其它缓存配合使用）
     */
    @Bean
    public Caffeine caffeineConfig() {
        Caffeine caffeine = Caffeine.newBuilder()
                .recordStats(() -> cacheStatsCounter)
//                .softValues()//使用软引用存储value, 如果没有强引用这个value，则GC内存不足时允许回收该条目---部分请求会频繁gc导致继续查库
                .initialCapacity(50)//初始的缓存空间大小。
                .expireAfterWrite(20, TimeUnit.MINUTES)
                .maximumSize(1000);//缓存的最大数量。


        return caffeine;
    }

    @Bean
    public CacheManager cacheManager(Caffeine caffeine) {
        CaffeineCacheManager caffeineCacheManager = new CaffeineCacheManager();
        caffeineCacheManager.setCaffeine(caffeine);
        //允许为null
        caffeineCacheManager.setAllowNullValues(true);
        return caffeineCacheManager;
    }
}
